using DataAnalyticsTools.Core;
using DataAnalyticsTools.Models;
using GrapeCity.Forguncy.Commands;
using GrapeCity.Forguncy.Log;
using GrapeCity.Forguncy.Plugin;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;

namespace DataAnalyticsTools
{
    [Icon("pack://application:,,,/DataAnalyticsTools;component/Resources/Icon.png")]
    [Designer("DataAnalyticsTools.Designer.DataAnalyticsToolsServerCommandDesigner, DataAnalyticsTools")]
    [Category("数据分析")]
    [OrderWeight(320)]
    public class FeatureImportanceByPermutation : Command, ICommandExecutableInServerSideAsync, IServerCommandParamGenerator
    {
        [FormulaProperty]
        [DisplayName("样本特征矩阵")]
        [Description("float[][]二维数组，外层为样本，内层为该样本的各维度特征。")]
        public object featuresExpr { get; set; }

        [FormulaProperty]
        [DisplayName("样本标签数组")]
        [Description("int[]一维数组，表示每个样本所属的类别标签。")]
        public object labelsExpr { get; set; }

        [FormulaProperty]
        [DisplayName("特征名称数组")]
        [Description("string[]一维数组，表示每个特征维度的名称。")]
        public object featureNamesExpr { get; set; }


        [FormulaProperty]
        [DisplayName("置换次数")]
        public object permutationsExpr { get; set; } = 30;

        [FormulaProperty]
        [DisplayName("K值（KNN的“最近邻”个数）")]
        public object kExpr { get; set; } = 5;


        [ResultToProperty]
        [DisplayName("保存特征重要性到变量")]
        [Description("每个特征的性能损失比例在ImportanceScore属性")]
        public string ResultTo { get; set; } = "特征重要性";

        public async Task<ExecuteResult> ExecuteAsync(IServerCommandExecuteContext dataContext)
        {
            var features = await dataContext.EvaluateFormulaAsync(featuresExpr);
            var labels = await dataContext.EvaluateFormulaAsync(labelsExpr);
            var k = int.Parse((await dataContext.EvaluateFormulaAsync(kExpr))?.ToString() ?? "5");
            var permutations = int.Parse((await dataContext.EvaluateFormulaAsync(permutationsExpr))?.ToString() ?? "30");
            var featureNames = GeneralConvertors.ConvertToStringArray(await dataContext.EvaluateFormulaAsync(featureNamesExpr));

            // 执行计算
            var result = FeatureImportanceAnalyzer.CalculateByPermutation(
                 GeneralConvertors.ConvertToFloatMatrix(features),
                 GeneralConvertors.ConvertToIntArray(labels),
                 permutations,
                 k);

            List<FeatureImportanceInfo> finalResult = new List<FeatureImportanceInfo>();

            for (int i = 0; i < result.Length; i++)
            {
                var item = new FeatureImportanceInfo(i, result[i], featureNames.Length > i ? featureNames[i] : null);
                finalResult.Add(item);

            }

            dataContext.Parameters[ResultTo] = finalResult;

            return new ExecuteResult();
        }

        public override string ToString()
        {
            if (featuresExpr == null)
            {
                return "计算特征重要性（随机置换法）";
            }
            else
            {
                return "计算特征重要性（随机置换法）：" + ResultTo;
            }
        }

        public override CommandScope GetCommandScope()
        {
            return CommandScope.ExecutableInServer;
        }

        public IEnumerable<GenerateParam> GetGenerateParams()
        {
            yield return new GenerateListParam()
            {
                ParamName = this.ResultTo,
                Description = "特征重要性的计算结果",
                ParamScope = CommandScope.All,
                ItemProperties = new List<string>() {
                    "FeatureIndex",
                    "FeatureName",
                    "ImportanceScore",
                    "ImportanceLevel"
                }
            };
        }
    }
}
